package com.mr.dao.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.mr.dao.Dao;
import com.mr.model.BaseObject;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;

@Repository("baseDao")
public class BaseDaoHibernate implements Dao {
   protected final Logger log = LoggerFactory.getLogger(getClass());
   @Autowired@Qualifier("hibernateTemplate")
   protected HibernateTemplate hibernateTemplate;
   public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
      this.hibernateTemplate = hibernateTemplate;
   }
   
   public <T extends BaseObject> T saveObject(T entity) {
      hibernateTemplate.saveOrUpdate(entity);
      return entity;
   }
   
   public <T extends BaseObject> T getObject(Class<T> clazz, Serializable id) {
   	if(id==null||clazz==null) return null;
      T o = (T) hibernateTemplate.get(clazz, id);
      return o;
   }
   
   public <T extends BaseObject> List<T> getAllObjects(Class<T> clazz) {
   	if(clazz==null) return null;
      return hibernateTemplate.loadAll(clazz);
   }
   
   public <T extends BaseObject> T removeObject(Class<T> clazz, Serializable id) {
   	if(id==null||clazz==null) return null;
      T o = getObject(clazz, id);
      if( o!=null ) hibernateTemplate.delete(o);
      return o;
   }
   
   public <T extends BaseObject> T removeObject(T object){
      if(object != null) hibernateTemplate.delete(object);
      return object;
   }
   
   public <T extends BaseObject, S extends Serializable> List<T> getObjectList(Class<T> clazz, Collection<S> idList) {
		List<T> result = new ArrayList<T>();
		T obj = null;
		for(S id: idList){
			obj = getObject(clazz, id);
			if(obj != null) result.add(obj);
		}
		return result;
	}
   
   public <T extends BaseObject> void removeObjectList(Collection<T> entityList) {
		for(T entity: entityList){
			if(entity != null) removeObject(entity);
		}
	}
   
   public <T extends BaseObject> void saveObjectList(Collection<T> entityList) {
		for(T entity: entityList){
			if(entity != null) saveObject(entity);
		}
	}
   
   public <T extends BaseObject> int getObjectCount(Class<T> clazz){
      DetachedCriteria query = DetachedCriteria.forClass(clazz);
      query.setProjection(Projections.rowCount());
      List result = hibernateTemplate.findByCriteria(query);
      if(result.isEmpty()) return 0;
      return Integer.parseInt("" + result.get(0));
   }
   
   public <T extends BaseObject> T removeObjectById(Class<T> clazz, Serializable id) {
      T entity = getObject(clazz, id);
      if(entity == null) return null;
      removeObject(entity);
      return entity;
   }
	
	public <T extends BaseObject> T updateObject(T entity) {
		hibernateTemplate.update(entity);
		return entity;
	}
	
	public <T extends BaseObject> T addObject(T entity) {
		hibernateTemplate.save(entity);
		return entity;
	}
	
	public <T extends BaseObject> void addObjectList(Collection<T> entityList) {
		for(T entity: entityList){
			if(entity != null) addObject(entity);
		}
	}
	
	public <T extends BaseObject> List<T> getObjectList(Class<T> clazz, String orderField, boolean asc){
		DetachedCriteria query = DetachedCriteria.forClass(clazz);
		if(asc) query.addOrder(Order.asc(orderField));
		else query.addOrder(Order.desc(orderField));
		return hibernateTemplate.findByCriteria(query);
	}
	
   public <T extends BaseObject> void saveObjectList(T... entityList) {
		for(T entity: entityList){
			if(entity!= null) saveObject(entity);
		}
   }
	
   public <T extends BaseObject> Map getObjectPropertyMap(Class<T> clazz, String keyname, String valuename){
		Map result = new HashMap();
		DetachedCriteria query = DetachedCriteria.forClass(clazz);
		query.setProjection(Projections.projectionList()
				.add(Projections.property(keyname), keyname)
				.add(Projections.property(valuename), valuename));
		query.setResultTransformer(DetachedCriteria.ALIAS_TO_ENTITY_MAP);
		List<Map> entryList = hibernateTemplate.findByCriteria(query);
		for(Map entry: entryList) result.put(entry.get(keyname), entry.get(valuename));
		return result;
	}

}

